#include "stdafx.h"
#include "../Engine/CamerManager.hpp"

namespace he
{
	namespace
	{
		static char const * camera_node = "CameraNode";
	}

	CameraManager::CameraManager(Ogre::SceneManager &SceneManager, Ogre::RenderWindow &RenderWindow, std::string const &Camera)
		: m_SceneManager(SceneManager),
		m_pCamera(m_SceneManager.createCamera(Camera)),
		m_Angle(30.f),
		m_pViewPort(RenderWindow.addViewport(m_pCamera)),
		m_DebugCamera(false)
	{
		m_pCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
		// Set the background
		m_pViewPort->setBackgroundColour(Ogre::ColourValue(212.0f/255.0f, 208.0f/255.0f, 200.0f/255.0f, 1.0f)); 
		// Create scene node for camera
		m_SceneManager.getRootSceneNode()->createChildSceneNode(camera_node)->attachObject(m_pCamera);
		// Default camera position
		m_pCamera->setPosition(Ogre::Vector3(0, 0, 0));
		// Rotate camera for given angle
		m_pCamera->setOrientation(Ogre::Quaternion(Ogre::Degree(m_Angle), Ogre::Vector3(-1, 0, 0)));
	}

	void CameraManager::set_camera_position(float WorldWidth, float WorldHeight, float MaxY)
	{
		// Constant offset
		static float const offset = 20;
		// Compute length of line of sight AFTER (below) the base plane
		float qx = (WorldHeight * Ogre::Math::Cos(Ogre::Degree(m_Angle)) + 2 * MaxY)/ (2 * Ogre::Math::Sin(Ogre::Degree(m_Angle)));
		// Compute the whole line of sight without offset
		float xw = (WorldHeight * Ogre::Math::Cos(Ogre::Degree(m_Angle)) + 2 * MaxY) / Ogre::Math::Sin(Ogre::Degree(m_Angle));
		// The whole length of line of sight from camera till the base plane
		float pos = xw - qx + offset;
		// Set camera position and frustum
		m_pCamera->setPosition(Ogre::Vector3(0, Ogre::Math::Sin(Ogre::Degree(m_Angle)) * pos, Ogre::Math::Cos(Ogre::Degree(m_Angle)) * pos));
		m_pCamera->setNearClipDistance(offset);
		m_pCamera->setFarClipDistance(offset + xw);
		// Set the dimensions with wide aspect ration
		m_pCamera->setOrthoWindow(WorldWidth * 1.333f, WorldHeight);
	}

	void CameraManager::switch_debug_camera()
	{
		
		static char const * debug_camera_perspective = "DebugCamPerspective";
		// Not enabled
		if(!m_DebugCamera)
		{
			m_pCamera->setDebugDisplayEnabled(true);
			m_pCamera->setVisible(true);
			// Create perspective camera
			Ogre::Camera *p_camera_pers = m_SceneManager.createCamera(debug_camera_perspective);
			p_camera_pers->setProjectionType(Ogre::PT_PERSPECTIVE);
			p_camera_pers->setPosition(Ogre::Vector3(50, 40, 15));
			p_camera_pers->lookAt(Ogre::Vector3(-0.5f, -0.5f, 15));
			p_camera_pers->setNearClipDistance(10);
			p_camera_pers->setVisible(true);
			p_camera_pers->setDebugDisplayEnabled(true);
			// Attach to viewport
			m_pViewPort->setCamera(p_camera_pers);
		}
		else
		{
			// Destroy original camera
			m_SceneManager.destroyCamera(m_pViewPort->getCamera());
			// Select original camera
			m_pViewPort->setCamera(m_pCamera);
			// Remove debug attributes
			m_pCamera->setVisible(false);
			m_pCamera->setDebugDisplayEnabled(false);
		}
		m_DebugCamera = !m_DebugCamera;
	}

	Ogre::Camera const &CameraManager::main_camera() const
	{
		return *m_pCamera;
	}

	Ogre::Camera &CameraManager::main_camera()
	{
		return *m_pCamera;
	}

	void CameraManager::move_main_camera_relative(Ogre::Vector3 const &Pos)
	{
		m_SceneManager.getSceneNode(camera_node)->translate(Pos);
	}
} /*he*/
